/// <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); } } }
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); }
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(); } }